package crp.core.security.domain.services.token;

import crp.core.security.domain.config.SecurityJwtConfig;
import crp.core.security.domain.messages.SecurityMessages;
import crp.core.security.domain.models.AccessToken;
import crp.core.security.domain.models.CallerPrincipal;
import io.quarkus.security.identity.SecurityIdentity;
import io.smallrye.jwt.build.Jwt;
import lombok.extern.slf4j.Slf4j;

import javax.enterprise.context.Dependent;
import javax.inject.Inject;
import java.util.Optional;

@Dependent
@Slf4j
public class AccessTokenBuilder {

    private final SecurityJwtConfig jwtConfig;

    @Inject
    public AccessTokenBuilder(SecurityJwtConfig jwtConfig) {
        this.jwtConfig = jwtConfig;
    }

    public AccessToken create(SecurityIdentity securityIdentity) {
        return Optional.ofNullable(securityIdentity)
                .map(SecurityIdentity::getPrincipal)
                .map(principal -> {
                    if (principal instanceof CallerPrincipal) {
                        return createCallerToken((CallerPrincipal) principal);
                    }
                    throw SecurityMessages.INSTANCE.invalidIdentity(principal.getName());
                })
                .orElseThrow(SecurityMessages.INSTANCE::createTokenFailed);
    }

    public AccessToken createCallerToken(CallerPrincipal principal) {
        String token = Jwt.upn(createUpn(principal))
                .claim(AccessTokenClaims.CALLER_PRINCIPAL_ID, principal.getName())
                .claim(AccessTokenClaims.CALLER_PRINCIPAL_TYPE, principal.getType())
                .issuer(jwtConfig.issuer())
                .expiresIn(jwtConfig.lifespan())
                .jws()
                .sign();
        return new AccessToken(principal.getName(), principal.getType(), token, jwtConfig.lifespan());
    }

    private String createUpn(CallerPrincipal principal) {
        return String.format("%s-%s", principal.getType(), principal.getName());
    }
}
